package com.atguigu.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import lombok.RequiredArgsConstructor;
import org.apache.http.HttpHeaders;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @author Fxz
 * @version 1.0
 * @date 2022-02-15 18:11
 */
@Component
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter {

	@Value("${authUrls.url}")
	private String authUrl;

	private final RedisTemplate redisTemplate;

	private final AntPathMatcher antPathMatcher = new AntPathMatcher();

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		ServerHttpRequest request = exchange.getRequest();
		String path = request.getURI().getPath();

		// 判断用户是否访问了内部接口
		if (antPathMatcher.match("/**/inner/**", path)) {
			ServerHttpResponse response = exchange.getResponse();
			return out(response, ResultCodeEnum.PERMISSION);
		}

		String userId = getUserId(request);
		String userTempId = getUserTempId(request);

		if ("-1".equals(userId)) {
			ServerHttpResponse response = exchange.getResponse();
			return out(response, ResultCodeEnum.PERMISSION);
		}

		// 判断用户是否访问了需要鉴权的接口
		String[] split = authUrl.split(",");
		for (String url : split) {
			if (path.contains(url) && StringUtils.isEmpty(userId)) {
				// 重定向到登录页面
				ServerHttpResponse response = exchange.getResponse();
				response.setStatusCode(HttpStatus.SEE_OTHER);
				response.getHeaders().set(HttpHeaders.LOCATION,
						"http://passport.gmall.com/login.html?originUrl=" + request.getURI());
				return response.setComplete();
			}
		}

		// 需要登录
		if (antPathMatcher.match("/api/**/auth/**", path) && StringUtils.isEmpty(userId)) {
			ServerHttpResponse response = exchange.getResponse();
			return out(response, ResultCodeEnum.LOGIN_AUTH);
		}

		// 验证通过 将用户id传递给后台微服务
		if (!StringUtils.isEmpty(userId)) {
			// 将用户id放到请求头
			return chain.filter(exchange.mutate().request(request.mutate().header("userId", userId).build()).build());
		}

		// 验证通过 将用户临时id传递给后台微服务
		if (!StringUtils.isEmpty(userTempId)) {
			// 将用户临时id放到请求头
			return chain.filter(
					exchange.mutate().request(request.mutate().header("userTempId", userTempId).build()).build());
		}

		// 放行
		return chain.filter(exchange);
	}

	/**
	 * 获取临时用户id
	 */
	private String getUserTempId(ServerHttpRequest request) {
		HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
		if (org.apache.commons.lang3.ObjectUtils.isNotEmpty(httpCookie)) {
			return httpCookie.getValue();
		}
		List<String> userTempId = request.getHeaders().get("userTempId");
		if (!CollectionUtils.isEmpty(userTempId)) {
			return userTempId.get(0);
		}
		return "";
	}

	private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum permission) {
		Result<Object> result = Result.build(null, permission);
		// 将result输出到页面
		String jsonString = JSON.toJSONString(result);
		response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
		DataBuffer wrap = response.bufferFactory().wrap(jsonString.getBytes());
		return response.writeWith(Mono.just(wrap));
	}

	/**
	 * 获取用户id
	 */
	private String getUserId(ServerHttpRequest request) {
		String token = "";
		List<String> stringList = request.getHeaders().get("token");
		if (CollectionUtils.isEmpty(stringList)) {
			HttpCookie httpCookie = request.getCookies().getFirst("token");
			if (!ObjectUtils.isEmpty(httpCookie)) {
				token = httpCookie.getValue();
			}
		}
		else {
			token = stringList.get(0);
		}
		String userKey = "user:login:" + token;
		String str = (String) redisTemplate.opsForValue().get(userKey);
		if (!StringUtils.isEmpty(str)) {
			JSONObject jsonObject = JSON.parseObject(str);
			String userId = jsonObject.getString("userId");
			String ip = jsonObject.getString("ip");
			String ipAddress = IpUtil.getGatwayIpAddress(request);
			if (ipAddress.equals(ip)) {
				return userId;
			}
			return "-1";
		}
		return null;
	}

}
